#include <stdlib.h>
#include <stdio.h>
#include <nds.h>

// common headers
#include "common.h"	// global

// local headers

#include "list.h"

u32 _il_hash(char *s, char *p) {
	if(!s && !p) return 0;	// return 0 on fail

	char *ss=s;
	char *sp=p;

	u32 h=0x13375336;	// seed

	if(ss && sp)
		while(*s && *p) {
			h+=((*s++)<<(h&1?16:0))+((*p++)<<(h&1?0:16));
		}

	if(ss)
		while(*s) {
			h+=((*s++)<<(h&1?8:24));
		}

	if(sp)
		while(*p) {
			h+=((*p++)<<(h&1?24:8));
		}

	return h?h:0xDEADBEEF;	// never return 0 on success
}

int il_add(sINI *ini, char *section, char *param, char *value) {
	if(!ini || (!section && !param)) return 1;

	sINIList *n=(sINIList *)x->xcalloc(1, sizeof(sINIList));

	n->section=section;
	n->param=param;
	n->hash=_il_hash(section, param);

	n->value=value;

//std->iprintf("add(%s, %s, %s, 0x%08x)\n", section, param, value, n->hash);

	if(ini->first) {	// insert 'n' between 'ini->first' and 'ini->first->prev' (aka the last element)
		ini->first->prev->next=n;
		n->prev=ini->first->prev;
		ini->first->prev=n;
		n->next=ini->first;
	}
	else {
		ini->first=n;
		ini->first->prev=ini->first;
		ini->first->next=ini->first;

		ini->next=ini->first;
	}

	return 0;
}

int il_get(sINI *ini, char *section, char *param, char **value) {
	if(!ini || (!section && !param)) return 1;

	u32 h=_il_hash(section, param);

	sINIList *il=ini->next?ini->next:ini->first;
	sINIList *st=il;

	while(il) {
		if(il->hash==h && !std->strcmp(il->section, section) && !std->strcmp(il->param, param)) {
			ini->next=il->next;
			if(value) *value=il->value;
			return 0;
		}

		il=il->next;
		if(il==st) {
			ini->next=st;
			break;
		}
	}

	return 1;
}

int il_getFirst(sINI *ini, char **section, char **param, char **value) {
	if(!ini || !ini->first) return 1;

	if(section)	*section=ini->first->section;
	if(param)	*param=ini->first->param;
	if(value)	*value=ini->first->value;

	ini->next=ini->first->next;

	return 0;
}

int il_getNext(sINI *ini, char **section, char **param, char **value) {
	if(!ini || !ini->next || ini->next==ini->first) return 1;

	if(section)	*section=ini->next->section;
	if(param)	*param=ini->next->param;
	if(value)	*value=ini->next->value;

	ini->next=ini->next->next;

	return 0;
}

void il_removeFree_h(char *section, char *param, char *value) {
	if(section)	x->xfree(section);
	if(param)	x->xfree(param);
	if(value)	x->xfree(value);
}

int il_removeAll(sINI *ini, il_remove_handler free_h) {
	if(!ini) return 1;
	if(!ini->first) return 0;

	sINIList *nil=ini->first, *prev;
	do {
		if(free_h) free_h(nil->section, nil->param, nil->value);

		prev=nil->prev;
		x->xfree(nil);
		nil=prev;
	} while(nil!=ini->first);

	ini->first=NULL;
	ini->next=NULL;

	return 0;
}

